iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0
自我挑戰組

30 天 vueuse 原始碼閱讀與實作系列 第 8

[Day 8] useEventListener - 參數介紹 & 核心 tryOnScopeDispose

  • 分享至 

  • xImage
  •  

官方 Demo:https://vueuse.org/core/useEventListener/#useeventlistener

先來說說 useEventListener 這個 API 可以帶來什麼好處~

在寫 Vue 的時候,如果在組件掛載之後有做 DOM event listeners 之類的 side effects,會需要在組件 onUnmounted 的時候移除事件監聽,
如果使用 useEventListener 來註冊事件監聽,就會在組件 onUnmounted 的時候自動移除事件監聽,不用再自己動手寫 removeEventListener,程式碼也會簡潔許多。

參數介紹

  • target :傳入要加上 eventListener 的 target,像是 window 或是 HTML element,也可以是 vue3 中的 ref。另外也是可以傳入 null 或是 undefined,不過就不會被 useEventListener 處理,完全不傳 target 的話,預設會是 window。
  • event :要監聽的事件名稱 。只有一個的話可以傳 string,多個的話就傳入 Array<string>
  • listener :傳入在觸發監聽的事件時,要執行的 function。跟 event 一樣,只有一個的話可以傳入 function 就好,多個的話就傳入 Arrayable<Function>
  • options :就是 addEventListener 本身可以傳入的 options object。像是 capture, once, passive, signal
// src/compositions/useEventListener.js
export function useEventListener(target, event, listener, options) {
  let _target
  let events
  let listeners
  let _options = options

  if (typeof target === 'string' || Array.isArray(target)) {
    _target = defaultWindow
  }
  _target = target
  events = event
  listeners = listener
  _options = options

  if (!_target)
    return noop

  if (!Array.isArray(events))
    events = [events]
  if (!Array.isArray(listeners))
    listeners = [listeners]
  
  // ...略
};

以上是 useEventListener 對參數處理的部分。

tryOnScopeDispose

要做到自動在組件註銷前 removeEventListener 的關鍵是 tryOnScopeDispose

// src/compositions/useEventListener.js
import { getCurrentScope, onScopeDispose } from 'vue'

export function tryOnScopeDispose(fn) {
  if (getCurrentScope()) {
    onScopeDispose(fn)
    return true
  }
  return false
}

export function useEventListener(target, event, listener, options) {
  // ...略
    
  const stop = () => {
    stopWatch()
    cleanup()
  }

  tryOnScopeDispose(stop)
}

這邊用到兩個 Vue 的 API:

  1. getCurrentScope():獲取當前的響應式效果作用域(reactive effect scope)。scope 可以是組件 instance 建立時自動生成的,也可以是通過 effectScope() 手動創建的。在 useEventListener 的情境中,通常會在組件的 setup() 函數中調用,所以拿到的會是組件的 scope。

  2. onScopeDispose(fn):註冊一個 callback function,該函數將在當前 scope 被銷毀時執行。跟 onUnmounted 類似,但因為它不需要在組件內部調用,所以很適合在 composable function 使用。

source:https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md#getting-the-current-scope

在我們知道可以在 composable function 中達成在 effect scope 消除時透過 onScopeDispose 來做些事情,那要傳什麼 function 給 onScopeDispose 讓他執行呢?

在上面程式碼中,傳入的是 stop,在組件 onUnmounted 的時候執行 composable function 內部的 stopWatch 以及 cleanup,cleanup 做的事情就是 removeEventListener。


今天看到了兩個平常比較少用的 Vue API,getCurrentScope() & onScopeDispose(fn),看起來是在寫多組件共用的 composable function 會非常實用,明天會接著把整個 useEventListener 的運作流程一起講完~


上一篇
[Day 7] useParallax - 序章
下一篇
[Day 9] useEventListener - 主要流程
系列文
30 天 vueuse 原始碼閱讀與實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言